# ScrollMenu - Menu widget that contains text items.
# Copyright (C) 2007 Lauri Taimila
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

__licence__ = "GPLv2"
__copyright__ = "2007, Lauri Taimila"
__author__ = "Lauri Taimila <lauri@taimila.com>"

import time
import gobject
import clutter
from clutter.cluttercairo import CairoTexture

class ScrollMenu(clutter.Group):
    """
    Menu widget that contains text items. Menu can be scrolled up and down.
    
    - Options: zoom, opacity, display N items, display arrows top+down
    - add Clutter labels
    - go around (how to implement this) (On state_change move items from start->back)
    """
    
    def __init__(self, item_gap, item_height, animated=False):
        """
        Initialize Menu
        @param item_gap: Gap between menuitems in pixels
        """
        clutter.Group.__init__(self)
        self.__active = True
        self.__clip_size = -1
        self.__items = []
        self.__gap = item_gap
        self.__item_height = item_height
        self.__animated = animated
        
    def add(self, actor):
        """
        Add new menuitem to the menu.
        @param item: clutter.Actor
        """
        clutter.Group.add(self, actor)
        
        y = (len(self.__items) * self.__item_height) + (self.__gap * len(self.__items))
        actor.set_position(0,y)
        actor.show()
        
        self.__items.append(actor)
        try:
            self.__update_opacity()
        except:
            pass
        
    def remove(self, actor):
        """
        Remove actor from the menu.
        """
        clutter.Group.add(self, actor)
        for item in self.__items:
            if item is actor:
                del item
    
    def remove_all(self):
        """
        Remove all actors from the menu.
        """
        self.remove_all()
        del self.__items
        self.__items = []
    
#    def set_selector(self, selector):
#        """
#        Set selector texture. Selector is a texture that is displayed under
#        currently selected menuitem. Selector does not move in ScrollMenu.
#        @param selector: Selector texture (Clutter.Actor)
#        """
#        selector.set_position(-10,190)
#        selector.set_size(200, self.__item_height)
#        
#        # Resize texture
#        x_scale = self.get_width() / float(selector.get_width())
#        y_scale = self.__item_height / float(selector.get_height())
#        selector.set_scale(x_scale, y_scale)
#
#        clutter.Group.add(self, selector)
#        for item in self.__items:
#            clutter.Group.lower(self, selector, item)
#        selector.show()
    
    def get_number_of_items(self):
        """Get number of menuitems in this Menu"""
        return len(self.__items)
    
    def set_number_of_visible_items(self, number):
        """
        Set how many menuitems are displayed on the screen at the same time.
        @param number: Number of items
        """
        self.__clip_size = number
        self.set_clip(0,
                      0,
                      self.get_width(), 
                      (self.__item_height + self.__gap) * number)
    
    def get_number_of_visible_items(self):
        """
        Get number of menuitems that are displayed on the screen at the same time.
        @return: Ingeter
        """
        return self.__clip_size
        
    def get_selected(self):
        """
        Get currently selected menuitem
        @return Clutter actor object
        """
        return self.__items[2]
        
    def scroll_down(self):
        """Scroll menu down by one menuitem."""
        if self.__animated:
            #FIXME: Animation doesn't work
            timeline = clutter.Timeline(7,26)
            alpha = clutter.Alpha(timeline, clutter.ramp_inc_func)
            behaviour = clutter.BehaviourPath(alpha, ((0,0),(0,self.__gap + self.__item_height)))
            for item in self.__items:
                behaviour.apply(self)
            timeline.start()
        else:
            for item in self.__items:
                item.move_by(0, self.__item_height + self.__gap)        
        
        # Set last item to first (menu scrolls)
        last = self.__items[-1]
        last.set_position(0, self.__items[0].get_y() - self.__gap - self.__item_height)
        self.__items = [last] + self.__items
        del self.__items[-1]
        
        self.__update_opacity()
        
    def scroll_up(self):
        """Scroll menu up by one menuitem."""
        if self.__animated:
            #FIXME: Animation doesn't work
            timeline = clutter.Timeline(7,26)
            alpha = clutter.Alpha(timeline, clutter.ramp_inc_func)
            behaviour = clutter.BehaviourPath(alpha, ((0,0),(0,-(self.__gap + self.__item_height))))
            for item in self.__items:
                behaviour.apply(item)
            timeline.start()
        else:
            for item in self.__items:
                item.move_by(0,-(self.__item_height + self.__gap))
        
        # Set first item to last (menu scrolls)
        first = self.__items[0]
        first.set_position(0, self.__items[-1].get_y() + self.__gap + self.__item_height)
        self.__items.append(first)
        del self.__items[0]
        
        self.__update_opacity()
    
    def is_active(self):
        """
        Is this menu active.
        @return boolean, True if menu is currently active, otherwise False
        """
        return self.__active
    
    def set_active(self, boolean):
        """
        Set this widget active or inactive
        @param boolean: True to set widget active, False to set inactive
        """
        self.__active = boolean
        if boolean:
            #if self.__selector is not None:
            #    self.__selector.show()
            self.set_opacity(255)
        else:
            #if self.__selector is not None:
            #    self.__selector.hide()
            self.set_opacity(128)
        
    def __update_opacity(self):
        """Update menuitem opacities"""
        self.__items[2].set_opacity(255)
        
        self.__items[1].set_opacity(128)
        self.__items[3].set_opacity(128)
        
        self.__items[0].set_opacity(64)
        self.__items[4].set_opacity(64)